package com.polaris.live.ui.live.activity

import android.app.Activity
import android.os.Bundle
import android.view.MotionEvent
import android.view.TextureView
import android.view.View
import android.view.WindowManager
import androidx.core.os.bundleOf
import androidx.fragment.app.Fragment
import com.blankj.utilcode.util.AppUtils
import com.blankj.utilcode.util.Utils
import com.polaris.live.R
import com.polaris.live.common.constant.ServerConfig
import com.polaris.live.common.ext.setOnSingleClickListener
import com.polaris.live.constant.LiveConst
import com.polaris.live.databinding.ActivityLiveVideoBinding
import com.polaris.live.im.manager.ImCallManager
import com.polaris.live.im.manager.OnLiveObserveListener
import com.polaris.live.im.sfs.COMMAND_CALL_CANCEL
import com.polaris.live.im.sfs.COMMAND_CALL_END
import com.polaris.live.im.sfs.COMMAND_CALL_START
import com.polaris.live.im.sfs.COMMAND_CALL_START_WAIT
import com.polaris.live.im.sfs.bean.live.CallSignalingMessage
import com.polaris.live.im.sfs.bean.live.LiveRoomInfo
import com.polaris.live.manager.LiveStateManager
import com.polaris.live.popup.ContributionListPopup
import com.polaris.live.resp.back_resp.CallStartResp
import com.polaris.live.resp.back_resp.CallVo
import com.polaris.live.resp.back_resp.RecognizeModel
import com.polaris.live.resp.back_resp.ScreenshotStrategyVo
import com.polaris.live.resp.event.LoginZegoEvent
import com.polaris.live.ui.game.GameUtils
import com.polaris.live.ui.live.activity.base.BaseLiveActivity
import com.polaris.live.ui.live.bean.LiveInitInfo
import com.polaris.live.ui.live.fragment.CallVideoFragment
import com.polaris.live.ui.live.fragment.GameCallVideoFragment
import com.polaris.live.ui.live.fragment.LiveMatchFragment
import com.polaris.live.ui.live.fragment.LiveVideoFragment
import com.polaris.live.ui.live.fragment.base.OnGestureListener
import com.polaris.live.ui.live.proxy.LiveStreamProxy
import com.polaris.live.ui.live.proxy.LiveTranslationProxy
import com.polaris.live.ui.live.widget.LiveVideoLoadingView
import com.polaris.live.ui.live.widget.OnLiveAnswerListener
import com.polaris.live.ui.live.widget.listener.OnBackPressedListener
import com.polaris.live.ui.live.widget.listener.OnCallTranslationListener
import com.polaris.live.ui.live.widget.listener.OnGameCallListener
import com.polaris.live.ui.live.widget.listener.OnLiveCallCallback
import com.polaris.live.ui.live.widget.listener.OnLiveEventListener
import com.polaris.live.ui.live.widget.listener.OnLiveNetworkListener
import com.polaris.live.ui.live.widget.listener.OnLiveStateSwitchListener
import com.polaris.live.ui.live.widget.listener.OnPlayFirstFrameListener
import com.polaris.live.ui.live.widget.listener.OnPublishFirstFrameListener
import com.polaris.live.ui.live.widget.listener.OnTranslationChangeListener
import com.polaris.live.utils.XActivityUtils
import com.polaris.live.utils.fragment.attachFragment
import com.polaris.live.utils.route.RoutePath
import com.polaris.live.utils.route.Router
import com.polaris.live.utils.zego.LiveActivityIdentifier
import com.polaris.live.utils.zego.LiveEngineManage
import com.polaris.live.utils.zego.beauty.OnFaceStateChangeListener
import com.polaris.live.viewmodel.live.LiveVideoViewModel
import im.zego.zegoexpress.constants.ZegoPublisherState
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import org.json.JSONObject

/**
 * 直播页面
 *
 * @author Created by lucas on 2023/11/10 15:12
 * @since 1.0.0
 */
class LiveVideoActivity : BaseLiveActivity<LiveVideoViewModel, ActivityLiveVideoBinding>(),
    OnFaceStateChangeListener,
    OnLiveAnswerListener,
    OnPublishFirstFrameListener,
    OnPlayFirstFrameListener,
    OnLiveCallCallback,
    OnCallTranslationListener,
    OnTranslationChangeListener,
    OnGameCallListener {

    private lateinit var mLiveInfo: LiveRoomInfo
    private var mScreenshotStrategy: ScreenshotStrategyVo? = null

    private var mVideoLoading: LiveVideoLoadingView? = null

    private var mStage = NONE

    private var mCurrentFragment: Fragment? = null //当前的fragment

    private var mIsGameCall = true

    private val mLiveVideoFragment by lazy {
        if (mStage != NONE) {
            null
        } else {
            supportFragmentManager.attachFragment(R.id.fl_fragment_live) {
                LiveVideoFragment().apply {
                    arguments = bundleOf(
                        LiveConst.Params.LIVE_INFO to mLiveInfo,
                        LiveConst.Params.SCREENSHOT_STRATEGY to mScreenshotStrategy
                    )
                }
            }
        }
    }

    private val mLiveMatchFragment by lazy {
        if (mStage != NONE) {
            null
        } else {
            supportFragmentManager.attachFragment(R.id.fl_fragment_live) {
                LiveMatchFragment().apply {
                    arguments = bundleOf(
                        LiveConst.Params.LIVE_INFO to mLiveInfo,
                        LiveConst.Params.SCREENSHOT_STRATEGY to mScreenshotStrategy
                    )
                }
            }
        }
    }

    //获取通话fragment标签嵌入
    private fun getCallFragment(
        callBean: CallStartResp,
        callMessage: CallSignalingMessage,
    ): CallVideoFragment {
        return supportFragmentManager.attachFragment(R.id.fl_fragment_call) {
            CallVideoFragment().apply {
                arguments = bundleOf(
                    LiveConst.Params.CALL_BEAN to callBean,
                    LiveConst.Params.CALL_MESSAGE to callMessage,
                    LiveConst.Params.CALL_INFO to callBean.call,
                )
            }
        }.apply {
            setOnTranslateChangeListener(this@LiveVideoActivity)
        }
    }

    //获取游戏通话fragment标签嵌入
    private fun getGameCallFragment(
        callBean: CallStartResp,
        callMessage: CallSignalingMessage,
    ): GameCallVideoFragment {
        return supportFragmentManager.attachFragment(R.id.fl_fragment_call) {
            GameCallVideoFragment().apply {
                arguments = bundleOf(
                    LiveConst.Params.CALL_BEAN to callBean,
                    LiveConst.Params.CALL_MESSAGE to callMessage,
                    LiveConst.Params.CALL_INFO to callBean.call,
                )
            }
        }.apply {
            setOnTranslateChangeListener(this@LiveVideoActivity)
            setOnGameCallListener(this@LiveVideoActivity)
        }
    }

    private val mLiveStreamProxy by lazy {
        LiveStreamProxy(
            LiveActivityIdentifier.LIVE_VIDEO_ACTIVITY,
            this,
            mViewModel,
            LiveEngineManage.getEngine()
                ?: throw IllegalArgumentException("A fatal exception occurred, the video engine is not initialized"),
            mBinding.tvMain,
            mBinding.tvMinor,
            mBinding.tvMinor,
            this,
            this,
            this,
        )
    }

    //同声传译
    private val mLiveTranslationProxy by lazy { LiveTranslationProxy(this) }

    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onLoginZegoEvent(event: LoginZegoEvent) {
        if (LiveStateManager.getState() == LiveConst.State.ONLY_LIVE || LiveStateManager.getState() == LiveConst.State.LIVE_AND_MATCH) {
            mLiveStreamProxy.startPublishStream(mLiveInfo.streamId)
        }
    }

    override fun initView(savedInstanceState: Bundle?) {
        super.initView(savedInstanceState)
        val initVariable = intent.getParcelableExtra<LiveInitInfo>(LiveConst.Params.LIVE_INIT_INFO)
        if (initVariable == null) {
            finish()
            return
        }

        mLiveInfo = initVariable.info
        mScreenshotStrategy = initVariable.screenshotStrategy

        window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)

        if (!ServerConfig.isTestServer()) {
            window.setFlags(
                WindowManager.LayoutParams.FLAG_SECURE,
                WindowManager.LayoutParams.FLAG_SECURE
            )
        }

        initView()
        initObserver()
        initListener()

        initFragment()
        initDate()
    }

    private fun initView() {
        mVideoLoading = LiveVideoLoadingView(this).apply {
            mBinding.cvMain.addView(this)
            loadCover(mLiveInfo.avatar)
        }

        //修改状态
        switchGlobalStateToLive()
    }

    private val onAppStatusChangedListener = object : Utils.OnAppStatusChangedListener {
        override fun onForeground(activity: Activity?) {
            if (!mViewModel.isForegroundClose) {
                selectJump(mViewModel.callInfo, mViewModel.callBean, mViewModel.callMessage)
                mViewModel.isForegroundClose = true
            }
        }

        override fun onBackground(activity: Activity?) {
        }
    }

    private fun initObserver() {
        AppUtils.registerAppStatusChangedListener(onAppStatusChangedListener)
        //通知电话
        ImCallManager.observe(this, { OnLiveObserveListener.ANY_ID }) {
            //来电，不需要等待
            withMessage<CallSignalingMessage>(COMMAND_CALL_START) {
                XActivityUtils.killTopActivityTo(this@LiveVideoActivity)
                onAnswer(it)
            }
            //来电，需要同意
            withMessage<CallSignalingMessage>(COMMAND_CALL_START_WAIT) {
                XActivityUtils.killTopActivityTo(this@LiveVideoActivity)
                getCurrentEventListener()?.onLivingToCall(it)
            }
            //对方取消了通话，todo 这里是事件需要确定
            withMessage<CallSignalingMessage>(COMMAND_CALL_CANCEL, COMMAND_CALL_END) {
                getCurrentEventListener()?.onCancelToCall(it)
            }
        }
        //接听成功
        mViewModel.callAnswerLiveData.observe(this) { (callMessage, callBean) ->
            mViewModel.callExitLive()

            ContributionListPopup.dismissPop() //关闭掉大哥排行榜

            toCallStage(callMessage, callBean)
        }
        //等待结束
        mViewModel.callEndWaitLiveData.observe(this) {
            toLiveStage()
        }
    }

    private fun initListener() {
        mBinding.cvMinor.setOnSingleClickListener {
            mLiveStreamProxy.switchPlayView()
        }
    }

    private fun initFragment() {
        mCurrentFragment = if (mLiveInfo.type == LiveConst.Type.ONLY_MATCH) {
            mLiveMatchFragment
        } else {
            mLiveVideoFragment
        }

        getCurrentEventListener()?.setOnLiveCallCallback(this)
        getCurrentEventListener()?.setOnLiveAnswerListener(this)

        mStage = LIVE
    }

    private fun initDate() {
        mLiveStreamProxy.startPublishStream(mLiveInfo.streamId)
    }

    //---------- 以下是回调方法
    override fun onAnswer(message: CallSignalingMessage, needLoading: Boolean) {
        //如果阶段是不允许改变的无视
        if (cannotChange(CALL)) {
            return
        }

        mViewModel.answerCall(message, LiveConst.AnswerType.AGREE, needLoading)
    }

    override fun onRefuse(message: CallSignalingMessage, type: Int) {
        mViewModel.answerCall(message, LiveConst.AnswerType.REFUSE)
    }

    override fun onPublishFirstFrame() {
        mVideoLoading?.run {
            mBinding.cvMain.removeView(this)
        }
        mVideoLoading = null
    }

    override fun onPublisherStateUpdate(
        streamID: String?,
        state: ZegoPublisherState?,
        errorCode: Int,
        extendedData: JSONObject?,
    ) {
        if (errorCode != 0) {
            //推流状态出错
        }
        if (state == ZegoPublisherState.PUBLISHING) {
            //正在推流中
        } else if (state == ZegoPublisherState.NO_PUBLISH) {
            //未推流
        } else if (state == ZegoPublisherState.PUBLISH_REQUESTING) {
            //正在请求推流中
        }
    }

    override fun onPlayFirstFrame() {
        if (!mIsGameCall) {
            //切换大小窗，并且显示view
            mBinding.cvMinor.visibility = View.VISIBLE
            mLiveStreamProxy.switchPlayView(mBinding.tvMinor)
        }
        mCurrentFragment?.also {
            if (it is OnPlayFirstFrameListener) {
                it.onPlayFirstFrame()
            }
        }
    }

    override fun setGameCallView(publishView: TextureView, playView: TextureView) {
        mLiveStreamProxy.setStartGameCallView(publishView, playView)
    }

    override fun onGameChangeCamera() {
        mLiveStreamProxy.changeCamera()
    }

    override fun onGameOpenCloseCamera(mCloseCamera: Boolean, publishView: TextureView) {
        mLiveStreamProxy.onGameOpenCloseCamera(mCloseCamera, publishView)
    }

    override fun onGameOtherOpenCloseCamera(mCloseCamera: Boolean, publishView: TextureView) {
        mLiveStreamProxy.onGameOtherOpenCloseCamera(mCloseCamera, publishView)
    }

    override fun onCallStop(
        callInfo: CallVo?,
        callBean: CallStartResp?,
        callMessage: CallSignalingMessage?,
        isForeground: Boolean,
    ) {

        mViewModel.isForegroundClose = isForeground
        mViewModel.callBean = callBean
        mViewModel.callMessage = callMessage
        mViewModel.callInfo = callInfo
        if (mViewModel.isForegroundClose) {
            selectJump(callInfo, callBean, callMessage)
        }

    }

    fun selectJump(
        callInfo: CallVo?,
        callBean: CallStartResp?,
        callMessage: CallSignalingMessage?,
    ) {

        //内部已经处理完成，这里转回状态
        toTransitionStage()

        if (callInfo != null) {
            Router.builder(RoutePath.LIVE_GAIN_CALL_END_ACTIVITY)
                .withAny(LiveConst.Params.CALL_INFO, callInfo)
                .withAnyNullable(LiveConst.Params.CALL_BEAN, callBean)
                .withAnyNullable(LiveConst.Params.CALL_MESSAGE, callMessage)
                .withBoolean(LiveConst.Params.CALL_NEED_COUNTDOWN, true)
                .navigation(this)

            mViewModel.callEndWaitResume()
        } else {
            //这里说明里面出现了问题，直接回转到直播页面
            toLiveStage()
        }

    }

    override fun onChangeCamera() {
        mLiveStreamProxy.changeCamera()
    }

    override fun onResume() {
        super.onResume()

        //如果是转换状态则恢复推流
        if (mStage == TRANSITION) {
            toLiveStage()
        }
    }

    //---------- 最终修改状态，调用到这里必须保证状态是对的

    //切换到通话页面
    private fun toCallStage(senderInfo: CallSignalingMessage, callInfo: CallStartResp) {
        if (mStage == CALL) {
            return
        }
        GameUtils.dismissGameFragment(this)
        mIsGameCall = !senderInfo.getCallVo()?.gameMiniId.isNullOrEmpty()
        if (mIsGameCall) {
            mCurrentFragment = getGameCallFragment(callInfo, senderInfo).apply {
                mCurrentFragment?.also {
                    switchFragment(it, null)
                }
                setOnLiveCallCallback(this@LiveVideoActivity)
            }
        } else {
            mCurrentFragment = getCallFragment(callInfo, senderInfo).apply {
                mCurrentFragment?.also {
                    switchFragment(it, null)
                }
                setOnLiveCallCallback(this@LiveVideoActivity)
            }
        }
        mLiveStreamProxy.userFrontCamera()
        //切换流
        mLiveStreamProxy.startPublishStream(callInfo.call.pushStreamId)
        mLiveStreamProxy.startPlayStream(callInfo.call.playStreamId)

        LiveStateManager.changeStateForce(LiveConst.State.CALL)

        mStage = CALL
    }

    //切换到转场页面
    private fun toTransitionStage() {
        if (mStage == TRANSITION) {
            return
        }

        //暂停推流
        mLiveStreamProxy.resetPreview()

        mLiveStreamProxy.pausePublishStream()
        mLiveStreamProxy.stopPlayStream()

        mBinding.cvMinor.visibility = View.GONE

        val oldFragment = mCurrentFragment
        mCurrentFragment = if (isOnlyMatch()) {
            mLiveMatchFragment
        } else {
            mLiveVideoFragment
        }

        if (oldFragment != null) {
            mCurrentFragment?.also { switchFragment(oldFragment, it, true) }
        }


        switchGlobalStateToLive()

        mStage = TRANSITION
    }

    //回到直播状态
    private fun toLiveStage() {
        if (mStage == LIVE) {
            return
        }

        mViewModel.stopCallEndWaitResume()

        mLiveStreamProxy.resumePublishStream(mLiveInfo.streamId)

        //回来恢复直播间
        getCurrentEventListener()?.onRecoverLive()

        mStage = LIVE
    }

    private fun switchGlobalStateToLive() {
        if (mLiveInfo.type == LiveConst.Type.LIVE_AND_MATCH || mLiveInfo.type == LiveConst.Type.ONLY_MATCH) {
            LiveStateManager.changeStateForce(LiveConst.State.LIVE_AND_MATCH)
        } else {
            LiveStateManager.changeStateForce(LiveConst.State.ONLY_LIVE)
        }
    }

    private fun switchFragment(
        oldFragment: Fragment,
        newFragment: Fragment?,
        oldRemoved: Boolean = false,
    ) {
        if (newFragment != null) {
            supportFragmentManager.beginTransaction()
                .show(newFragment)
                .commitAllowingStateLoss()

            if (newFragment is OnLiveStateSwitchListener) {
                newFragment.onLiveResume()
            }
        }

        if (oldFragment is OnLiveStateSwitchListener) {
            oldFragment.onLivePause()
        }

        if (oldRemoved) {
            supportFragmentManager.beginTransaction()
                .remove(oldFragment)
                .commitAllowingStateLoss()
        } else {
            supportFragmentManager.beginTransaction()
                .hide(oldFragment)
                .commitAllowingStateLoss()
        }
    }

    private fun cannotChange(stage: Int) =
        (mStage == stage || (stage < mStage && mStage != TRANSITION && stage != LIVE))

    private fun isOnlyMatch() = mLiveInfo.type == LiveConst.Type.ONLY_MATCH

    private fun getCurrentEventListener(): OnLiveEventListener? {
        val fragment = mCurrentFragment
        return if (fragment is OnLiveEventListener) {
            fragment
        } else {
            null
        }
    }

    override fun onFaceStateChange(valid: Boolean) {
        mCurrentFragment?.also {
            if (it is OnFaceStateChangeListener) {
                it.onFaceStateChange(valid)
            }
        }
    }

    override fun onTranslating(model: RecognizeModel) {
        mCurrentFragment?.also {
            if (it is OnCallTranslationListener) {
                it.onTranslating(model)
            }
        }
    }

    override fun onTranslated(model: RecognizeModel) {
        mCurrentFragment?.also {
            if (it is OnCallTranslationListener) {
                it.onTranslated(model)
            }
        }
    }

    //同声传译开关
    override fun onTranslationSwitch(isOpen: Boolean, needUnInit: Boolean) {
        if (isOpen) {
            mLiveTranslationProxy.startTranslation()
        } else {
            mLiveTranslationProxy.stopTranslation(needUnInit)
        }
    }

    //修改同声传译语言
    override fun onTranslationLanguage(language: String) {
        mLiveTranslationProxy.setTranslationLanguage(language)
    }

    override fun onSetSpeechLanguage(language: String) {
        mLiveTranslationProxy.setSpeechLanguage(language)
    }

    override fun onInitTranslation(
        key: String,
        translationLanguage: String,
        speechLanguage: String,
    ) {
        mLiveTranslationProxy.initKey(key, translationLanguage, speechLanguage)
    }

    override fun onDestroy() {
        super.onDestroy()
        AppUtils.unregisterAppStatusChangedListener(onAppStatusChangedListener)
    }

    override fun onBackPressed() {
        val currentFragment = mCurrentFragment
        if (currentFragment is OnBackPressedListener) {
            if (!currentFragment.onBackPressed()) {
                super.onBackPressed()
            }
        } else {
            super.onBackPressed()
        }
    }

    override fun dispatchTouchEvent(ev: MotionEvent): Boolean {
        val currentFragment = mCurrentFragment
        return if (currentFragment is OnGestureListener) {
            currentFragment.dispatchTouchEvent(ev) || super.dispatchTouchEvent(ev)
        } else {
            super.dispatchTouchEvent(ev)
        }
    }

    override fun onNetwork(isNetwork: Boolean, isConnected: Boolean) {
        val currentFragment = mCurrentFragment
        if (currentFragment is OnLiveNetworkListener) {
            currentFragment.onNetwork(isNetwork, isConnected)
        }
    }

    companion object {

        //-----下列的阶段会从小切到大，只有3可以切换为1，其他的都是不可逆的

        const val NONE = 0 // 初始阶段，可以添加直播或者匹配fragment
        const val LIVE = 1 // 直播阶段
        const val CALL = 2 // 通话阶段
        const val TRANSITION = 3 // 切换阶段
        const val STOP = 4 // 结束阶段，不允许在回去

    }
}